using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace Sucrose.Base
{
    public delegate void LogMessageHandler(String message, MessageType type);

    public enum MessageType
    {
        None =      4,
        Debug =     3,
        Info =      2,
        Warning =   1,
        Error =     0,
    }

    public static class Logger
    {
        private const bool useConsole   = false;
        private const bool useFile      = true;
        private const String directory  = "Sucrose";
        private const short logLength   = 7;

        private static String fullPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
        private static MessageType threshold = MessageType.None;

        public static MessageType Threshold { get { return threshold; } set { threshold = value; } }

        public static event LogMessageHandler LogMessages;

        /// <summary>
        /// Checks that the log directory exists and removes logs that are older than the logLength constant. Also registers built in log listeners.
        /// </summary>
        static Logger()
        {
            fullPath += "\\" + directory + "\\logs";
            if (!Directory.Exists(fullPath))
                Directory.CreateDirectory(fullPath);

            String[] files = Directory.GetFiles(fullPath);
            foreach (String file in files)
            {
                DateTime fileTime = DateTime.Parse(file.Substring(file.LastIndexOf('\\') + 1, file.LastIndexOf('.') - file.LastIndexOf('\\') - 1));
                int diff = ((TimeSpan)(DateTime.Now - fileTime)).Days;
                if (diff > logLength)
                    File.Delete(file);
            }

            if(useFile)
                LogMessages += new LogMessageHandler(LogToFile);
            if(useConsole)
                LogMessages += new LogMessageHandler(LogToConsole);
        }

        /// <summary>
        /// Logs the passed message to the console or a file depending on how the constants are set. Defaults to the 'Info' message level.
        /// </summary>
        /// <param name="message">Message to be output</param>
        public static void Log(String message)
        {
            Logger.Log(message, MessageType.Info);
        }

        /// <summary>
        /// Fires LogMessages listeners
        /// </summary>
        /// <param name="message">Message to be output</param>
        /// <param name="type">Type of message. If at or below threshold, the event will not be fired</param>
        public static void Log(String message, MessageType type)
        {
            if (type < threshold)
            {
                if (LogMessages != null)
                    LogMessages.Invoke(message, type);

                Console.ForegroundColor = ConsoleColor.Gray;
            }
        }

        /// <summary>
        /// A Log to Console event handler. This outputs messags to the console.
        /// </summary>
        /// <param name="message">The message to output</param>
        /// <param name="type">The MessageType to print</param>
        private static void LogToConsole(String message, MessageType type)
        {
            Console.WriteLine(PrepareMessage(message, type));
        }

        /// <summary>
        /// A Log to File event handler. This outputs messages to a file.
        /// </summary>
        /// <param name="message">The message to log</param>
        /// <param name="type">The MessageType to log</param>
        private static void LogToFile(String message, MessageType type)
        {
            MessageType fileThreshold = MessageType.None;
            if (type < fileThreshold)
            {
                StreamWriter logFile = new StreamWriter(fullPath + "\\" + DateTime.Now.ToShortDateString().Replace("/", "-") + ".log", true);
                logFile.WriteLine(PrepareMessage(message, type));
                logFile.Flush();
                logFile.Close();
            }
        }

        /// <summary>
        /// Prepares a message in a string and sets the console color to either print to console or write to file.
        /// </summary>
        /// <param name="message">The message to prepare</param>
        /// <param name="type">The MessageType to prepare</param>
        /// <returns>A message suitable for output</returns>
        private static String PrepareMessage(String message, MessageType type)
        {
            switch (type)
            {
                case MessageType.Debug:
                    Console.ForegroundColor = ConsoleColor.Green;
                    message = " D: " + message;
                    break;
                case MessageType.Info:
                    Console.ForegroundColor = ConsoleColor.Gray;
                    message = " I: " + message;
                    break;
                case MessageType.Warning:
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    message = " W: " + message;
                    break;
                case MessageType.Error:
                    Console.ForegroundColor = ConsoleColor.Red;
                    message = " E: " + message;
                    break;
            }

            message = "(" + DateTime.Now.ToShortTimeString() + ")" + message;

            return message;
        }
    }
}
